<template>
  <div class="max-w-4xl mx-auto p-6">
    <h1 class="text-2xl font-semibold">图片旋转（Rotate）</h1>
    <p class="mt-2 text-gray-600">上传图片后可任意旋转角度、左右/上下翻转，预览并下载结果。</p>

    <div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
      <div>
        <label class="block mb-2 text-sm font-medium text-gray-700">选择图片</label>
        <div
          class="border-2 border-dashed border-gray-200 rounded-lg p-6 text-center hover:border-blue-300 transition-colors"
          @click="triggerFileInput"
        >
          <input ref="fileInput" type="file" accept="image/*" class="hidden" @change="onFileChange" />
          <div v-if="!originalDataUrl" class="text-gray-500">点击或拖拽上传图片（支持 JPEG / PNG / WEBP 等）</div>
          <div v-else class="flex flex-colitems-center">
            <img :src="originalDataUrl" alt="原始图片" class="max-h-48 object-contain mb-3 rounded" />
            <div class="text-sm text-gray-600">原始: {{ formatFileSize(originalSize) }} • {{ naturalWidth }} × {{ naturalHeight }}</div>
          </div>
        </div>

        <div class="mt-4 space-y-3">
          <div class="grid grid-cols-2 gap-3">
            <div>
              <label class="block text-sm text-gray-700 mb-1">旋转角度 (°)</label>
              <input type="number" v-model.number="angle" class="input-field w-full" min="-360" max="360" />
            </div>
            <div>
              <label class="block text-sm text-gray-700 mb-1">预设</label>
              <div class="flex space-x-2">
                <button @click="rotateLeft" class="inline-block px-3 py-2 border rounded text-sm">左转 90°</button>
                <button @click="rotateRight" class="inline-block px-3 py-2 border rounded text-sm">右转 90°</button>
                <button @click="normalizeAngle" class="inline-block px-3 py-2 border rounded text-sm">归一化</button>
              </div>
            </div>
          </div>

          <div>
            <label class="block text-sm text-gray-700 mb-1">滑动调整</label>
            <input type="range" min="-180" max="180" step="1" v-model.number="angle" class="w-full" />
          </div>

          <div class="flex items-center space-x-3">
            <label class="inline-flex items-center text-sm text-gray-700">
              <input type="checkbox" v-model="flipH" class="mr-2" /> 水平翻转
            </label>
            <label class="inline-flex items-center text-sm text-gray-700">
              <input type="checkbox" v-model="flipV" class="mr-2" /> 垂直翻转
            </label>
          </div>

          <div>
            <label class="block text-sm text-gray-700 mb-1">输出格式</label>
            <select v-model="options.format" class="input-field w-full">
              <option value="image/png">PNG (无损)</option>
              <option value="image/jpeg">JPEG (有损)</option>
              <option value="image/webp">WEBP</option>
            </select>
          </div>

          <div v-if="options.format !== 'image/png'" class="">
            <label class="block text-sm text-gray-700 mb-1">质量：<span class="font-medium">{{ Math.round(options.quality * 100) }}%</span></label>
            <input type="range" min="0.1" max="1" step="0.05" v-model.number="options.quality" class="w-full" />
          </div>

          <div class="flex space-x-2 mt-3">
            <button @click="doRotate" :disabled="!originalImage || processing" class="primary-button">{{ processing ? '处理中...' : '开始处理' }}</button>
            <button @click="reset" type="button" class="ml-2 inline-block px-4 py-2 border rounded text-sm" :disabled="processing">重置</button>
          </div>

          <div v-if="warnText" class="text-xs text-yellow-700 mt-2">{{ warnText }}</div>
        </div>
      </div>

      <div>
        <label class="block mb-2 text-sm font-medium text-gray-700">预览 & 下载</label>
        <div class="border rounded-lg p-4">
          <div v-if="!originalDataUrl" class="text-gray-500">尚未上传图片</div>

          <div v-else class="space-y-3">
            <div>
              <div class="text-sm font-medium">原图预览</div>
              <img :src="originalDataUrl" alt="原图" class="max-h-40 object-contain rounded mt-2" />
            </div>

            <div v-if="outputUrl">
              <div class="text-sm font-medium">处理后预览</div>
              <img :src="outputUrl" alt="结果" class="max-h-40 object-contain rounded mt-2" />
            </div>

            <div class="flex items-center justify-between">
              <div>
                <div class="text-xs text-gray-600">原始大小：{{ formatFileSize(originalSize) }}</div>
                <div v-if="outputBlob" class="text-xs text-gray-600">结果大小：{{ formatFileSize(outputSize) }}</div>
              </div>
              <div>
                <button v-if="outputBlob" @click="downloadResult" class="primary-button">下载</button>
              </div>
            </div>
          </div>
        </div>

        <nuxt-link to="/image-tools" class="mt-4 inline-block text-blue-500">返回图片工具</nuxt-link>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { useTools } from '@/composables/useTools'
useHead({ title: '图片旋转 - 图片工具' })

const { readImageFile, formatFileSize } = useTools()

const fileInput = ref(null)
const originalDataUrl = ref(null)
const originalImage = ref(null)
const originalSize = ref(0)
const naturalWidth = ref(0)
const naturalHeight = ref(0)

const angle = ref(0) // degrees
const flipH = ref(false)
const flipV = ref(false)

const options = ref({ format: 'image/png', quality: 0.9 })

const outputBlob = ref(null)
const outputUrl = ref(null)
const outputSize = ref(0)
const processing = ref(false)
const warnText = ref('')

const triggerFileInput = () => { fileInput.value && fileInput.value.click() }

const onFileChange = async (e) => {
  const f = e.target.files && e.target.files[0]
  if (!f) return
  if (!f.type.startsWith('image/')) {
    warnText.value = '请选择图片文件'
    return
  }
  warnText.value = ''
  originalSize.value = f.size
  try {
    const res = await readImageFile(f)
    originalDataUrl.value = res.dataUrl
    originalImage.value = res.image
    naturalWidth.value = res.image.naturalWidth || res.image.width
    naturalHeight.value = res.image.naturalHeight || res.image.height
    clearOutput()
  } catch (err) {
    console.error('读取图片失败', err)
    warnText.value = '读取图片失败，请检查文件。'
  }
}

const clearOutput = () => {
  if (outputUrl.value) URL.revokeObjectURL(outputUrl.value)
  outputBlob.value = null
  outputUrl.value = null
  outputSize.value = 0
}

const normalizeAngle = () => {
  // 把角度归一化到 -180..180
  let a = ((angle.value % 360) + 360) % 360
  if (a > 180) a -= 360
  angle.value = a
}

const rotateLeft = () => { angle.value = (angle.value - 90) % 360; normalizeAngle() }
const rotateRight = () => { angle.value = (angle.value + 90) % 360; normalizeAngle() }

const doRotate = async () => {
  if (!originalImage.value) return
  processing.value = true
  warnText.value = ''
  try {
    const img = originalImage.value
    const w = img.naturalWidth || img.width
    const h = img.naturalHeight || img.height
    const rad = (angle.value || 0) * Math.PI / 180
    const cos = Math.cos(rad)
    const sin = Math.sin(rad)
    const absCos = Math.abs(cos)
    const absSin = Math.abs(sin)

    // 计算旋转后画布所需尺寸
    const outW = Math.max(1, Math.round(w * absCos + h * absSin))
    const outH = Math.max(1, Math.round(w * absSin + h * absCos))

    const canvas = document.createElement('canvas')
    canvas.width = outW
    canvas.height = outH
    const ctx = canvas.getContext('2d')

    // 当输出为 jpeg 且源图有透明通道时提示
    if (options.value.format === 'image/jpeg') {
      try {
        const tmp = document.createElement('canvas')
        tmp.width = Math.min(10, w)
        tmp.height = Math.min(10, h)
        const tctx = tmp.getContext('2d')
        tctx.drawImage(img, 0, 0)
        const data = tctx.getImageData(0, 0, tmp.width, tmp.height).data
        for (let i = 3; i < data.length; i += 4) {
          if (data[i] < 255) {
            warnText.value = '注意：源图包含透明像素，导出为 JPEG 时透明区域会被填充为不透明颜色。'
            break
          }
        }
      } catch (e) {
        // ignore
      }
    }

    // 将原点移动到画布中心，执行旋转和翻转，再绘制图片使其中心对齐
    ctx.save()
    ctx.translate(outW / 2, outH / 2)
    ctx.rotate(rad)
    ctx.scale(flipH.value ? -1 : 1, flipV.value ? -1 : 1)
    ctx.drawImage(img, -w / 2, -h / 2, w, h)
    ctx.restore()

    await new Promise((resolve) => {
      canvas.toBlob((blob) => {
        if (!blob) {
          warnText.value = '处理失败：无法生成结果'
          processing.value = false
          resolve()
          return
        }
        clearOutput()
        outputBlob.value = blob
        outputUrl.value = URL.createObjectURL(blob)
        outputSize.value = blob.size
        resolve()
      }, options.value.format, options.value.quality)
    })

  } catch (err) {
    console.error(err)
    warnText.value = '处理时发生错误，请查看控制台。'
  } finally {
    processing.value = false
  }
}

const downloadResult = () => {
  if (!outputBlob.value) return
  const ext = mimeToExt(options.value.format)
  const filename = `rotated-${Date.now()}.${ext}`
  const url = URL.createObjectURL(outputBlob.value)
  const a = document.createElement('a')
  a.href = url
  a.download = filename
  a.click()
  URL.revokeObjectURL(url)
}

const mimeToExt = (mime) => {
  if (mime === 'image/jpeg') return 'jpg'
  if (mime === 'image/png') return 'png'
  if (mime === 'image/webp') return 'webp'
  return 'img'
}

const reset = () => {
  originalDataUrl.value = null
  originalImage.value = null
  originalSize.value = 0
  naturalWidth.value = 0
  naturalHeight.value = 0
  angle.value = 0
  flipH.value = false
  flipV.value = false
  options.value = { format: 'image/png', quality: 0.9 }
  clearOutput()
  warnText.value = ''
  if (fileInput.value) fileInput.value.value = null
}

</script>
